// +FHDR------------------------------------------------------------
//                 Copyright (c) 2024 NOVAUTO.
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : async_nbit_dmux.v
// Author        : ICer
// Created On    : 2024-03-14 14:37
// Last Modified : 2024-03-14 16:06 by ICer
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------


module async_nbit_dmux #(
  parameter DL = 2,
  parameter WD = 1,
  parameter FF = 1
)( /*AUTOARG*/
   // Outputs
   o_data, o_en,
   // Inputs
   i_clk, i_rst_n, i_data, i_en, o_clk, o_rst_n
   );

// ----------------------------------------------------------------
// Interface declare
// ----------------------------------------------------------------
input          i_clk;
input          i_rst_n;
input [WD -1:0]i_data;
input          i_en;

input          o_clk;
input          o_rst_n;
output[WD -1:0]o_data;
output         o_en;

// ----------------------------------------------------------------
// Wire declare
// ----------------------------------------------------------------

// ----------------------------------------------------------------
// i_data dff
// ----------------------------------------------------------------
wire [WD -1:0]i_data_in;
wire          i_en_in;
generate
  if(FF == 0)begin: NO_IN_DFF
    assign i_data_in = i_data;
    assign i_en_in   = i_en;
  end //if(FF == 0)begin: NO_IN_DFF
  else begin: IN_DFF
    reg [WD -1:0]i_data_ff;
    reg          i_en_ff;
    always @(posedge i_clk or negedge i_rst_n) begin
      if(!i_rst_n)begin
        i_data_ff <= {WD{1'b0}};
        i_en_ff   <= 1'b0;
      end
      else begin
        i_data_ff <= i_data;
        i_en_ff   <= i_en;
      end
    end
    assign i_data_in = i_data_ff;
    assign i_en_in   = i_en_ff;
  end //else begin: IN_DFF
endgenerate

// ----------------------------------------------------------------
// i_en_in async
// ----------------------------------------------------------------
wire i_en_sync;
reg  i_en_sync_ff;
wire i_en_sync_pulse;
reg  i_en_sync_pulse_ff;

async_1bit_delay #(.DL(DL), .FF(0))
u_i_en_sync(
  .i_clk    (i_clk),
  .i_rst_n  (i_rst_n),
  .i_data   (i_en_in),
  .o_clk    (o_clk),
  .o_rst_n  (o_rst_n),
  .o_data   (i_en_sync)
);

always @(posedge o_clk or negedge o_rst_n) begin
  if(!o_rst_n)
    i_en_sync_ff <= 1'b0;
  else
    i_en_sync_ff <= i_en_sync;
end

assign i_en_sync_pulse = (i_en_sync_ff == 1'b0) && (i_en_sync == 1'b1);

always @(posedge o_clk or negedge o_rst_n) begin
  if(!o_rst_n)
    i_en_sync_pulse_ff <= 1'b0;
  else
    i_en_sync_pulse_ff <= i_en_sync_pulse;
end

// ----------------------------------------------------------------
// i_data_in sample
// ----------------------------------------------------------------
reg [WD -1:0]i_data_sync;
always @(posedge o_clk or negedge o_rst_n) begin
  if(!o_rst_n)
    i_data_sync <= {WD{1'b0}};
  else if(i_en_sync_pulse)
    i_data_sync <= i_data_in;
end

// ----------------------------------------------------------------
// out logic
// ----------------------------------------------------------------
assign o_en   = i_en_sync_pulse_ff;
assign o_data = i_data_sync;

endmodule
// Local Variables:
// verilog-auto-inst-param-value:t
// verilog-library-directories:(".")
// verilog-library-extensions:(".v")
// End:

